/*
 * Process.cpp
 *
 */

#include "Process.h"
#include <string>
#include <wait.h>
#include <stdlib.h>
#include <errno.h>

#define CHILD_STDOUT_READ childStdout[0]
#define CHILD_STDOUT_WRITE childStdout[1]
#define CHILD_STDIN_READ childStdin[0]
#define CHILD_STDIN_WRITE childStdin[1]

Process::Process() {}

Process::Process(const std::string& command) {
	setCommand(command);
}

Process::~Process() {}

void Process::setCommand(const std::string& command) {
	std::stringstream comm(command);
	std::string param;
	while (comm >> param) {
		args.pushBack(param);
	}
}

void Process::exe() {
	if (pipe(childStdin) < 0)
		throw ProcessException("pipe creation failed");

	if (pipe(childStdout) < 0)
		throw ProcessException("pipe creation failed");

	processId = fork();
	if (processId == 0) {  // proceso hijo
		dup2(CHILD_STDIN_READ,0);  // direcciono stdin al pipe
		dup2(CHILD_STDOUT_WRITE, 1);  // direcciono stdout al pipe
		close(CHILD_STDIN_WRITE);
		close(CHILD_STDOUT_READ);  // no se usa, lo cierro
		execve(args.getFront(), args.get(), env.get());
	    exit(0);  // no se deberia llegar aca
	}
	else if (processId < 0) {  // fallo
		throw ProcessException("process launch failed");
	}
	else {  // proceso padre
		close(CHILD_STDIN_READ);  // no se usa, lo cierro
		close(CHILD_STDOUT_WRITE);  // no se usa, lo cierro
		stdcin.open(CHILD_STDIN_WRITE);
		stdcout.open(CHILD_STDOUT_READ);
	}
}

int Process::wait() {
	int status;
	::waitpid(processId, &status, NULL);
	return status;
}

void Process::addEnvVar(const std::string& name, const std::string& value) {
	std::string var = name + '=' + value;
	env.pushBack(var);
}

void Process::addArgument(const std::string& argument) {
	args.pushBack(argument);
}

IFdStream& Process::getCout() {
	return stdcout;
}

OFdStream& Process::getCin() {
	return stdcin;
}

void Process::kill() {
	int  killReturn = killpg(processId, SIGKILL);
	if (killReturn == EPERM) // no permitido
		throw ProcessException("Not allowed");
}

ProcessException::ProcessException(const std::string& msg) throw():
msg(msg) {}
